
#ifndef _data_packet_h
#define _data_packet_h

#include <vector>
#include "DataTypes.h"

class DataPacket {
  private:
    /**
      The actual data array has an underlying 1D representaton. The MPI vector
      data type expects data to be in a 1D format; the 'stride' parameter
      doesn't yields the correct element, when each row is a separate
      allocation.
      */

    CONTAINER_TYPE *data;

    int width, height;
    int new_w, new_h; 
    INT_PAIR ghost_cells; // 0 -> (j, x) 1 -> (i, y)

    std::vector< std::vector<int> > proc_map;

    MPI_Datatype column_type, row_type;
    
    bool common_init();
    void ghost_init();
    
    bool interchange_lr(MPI_Comm comm, int rank);
    bool interchange_tb(MPI_Comm comm, int rank);

    bool interchange_co(MPI_Comm comm, int rank);
    bool interchange_d0(MPI_Comm comm, int rank);
    bool interchange_d1(MPI_Comm comm, int rank);

  public:
    DataPacket(int width, int height, INT_PAIR ghost_cells);
    ~DataPacket();

    // Pointers to several locations in in the data container
    CONTAINER_TYPE *_l, *_r, *_t, *_b; // The four edges
    CONTAINER_TYPE *gl, *gr, *gt, *gb; // The ghost edges
    CONTAINER_TYPE *_ll, *_ul, *_lr, *_ur; // The four corners
    CONTAINER_TYPE *gll, *gul, *glr, *gur; // The ghost corners

    // Initialize the pointers and copy the data block
    bool init(const CONTAINER_TYPE *data_blk);
    bool init(const CONTAINER_TYPE val);

    // Set neighborhood map 
    inline void setProcMap(std::vector< std::vector<int> >& _proc_map) {
      proc_map = _proc_map;
    }

    CONTAINER_TYPE& access_data(int i, int j);

   // Interchange data between neighboring processes
   bool interchange(MPI_Comm comm, int rank);
};

#endif
